package com.ttbj.product.driver.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.ttbj.api.driver.DriverService;
import com.ttbj.api.dto.AccManageData;
import com.ttbj.api.dto.Page;
import com.ttbj.api.dto.driver.DriverDto;
import com.ttbj.api.exception.BusinessException;
import com.ttbj.api.yitong.YTFinancialService;
import com.ttbj.constant.AccTypeEnum;
import com.ttbj.constant.GenerateNumConstants;
import com.ttbj.constant.PlatFormErrorCode;
import com.ttbj.constant.annotation.SystemServiceLog;
import com.ttbj.constant.driver.DriverIsCompanyEnum;
import com.ttbj.constant.driver.DriverIsDelEnum;
import com.ttbj.constant.driver.DriverToExamineEnum;
import com.ttbj.core.constants.SmsEnum;
import com.ttbj.core.util.DateUtils;
import com.ttbj.core.util.DtoTransitionUtils;
import com.ttbj.core.util.JsonUtil;
import com.ttbj.core.util.MarkNumUtil;
import com.ttbj.core.util.RegexUtil;
import com.ttbj.core.util.SendSMSUtil;
import com.ttbj.driver.bean.po.Driver;
import com.ttbj.driver.bean.po.DriverComnum;
import com.ttbj.driver.dao.DriverComnumMapper;
import com.ttbj.driver.dao.DriverMapper;
import com.ttbj.product.ytpayutil.RandomCharData;


@Service("driverService")
public class DriverServiceImpl implements DriverService{
	
	@Autowired
	private DriverMapper driverMapper;
	@Autowired
	private DriverComnumMapper driverComnumMapper;
	@Autowired
	private YTFinancialService ytFinancialService;
	@Autowired
	private EhCacheCacheManager ehCacheCacheManager;
	
	private static final Logger logger = LoggerFactory.getLogger(DriverServiceImpl.class);
	
	
	@Override
	@Cacheable(value="findInfoUsedOrder")
	public DriverDto findDriverInfoById(Long driverId) throws BusinessException {
		if (null == driverId) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		Driver driver = this.driverMapper.queryDriverInfoById(driverId);
		DriverDto driverDto = (DriverDto) DtoTransitionUtils.trans(DriverDto.class, driver);
		return driverDto;
	}
	
	
	@Override
	public List<DriverDto> findDriverInfoByPage(Page page, DriverDto driverDto, String companyNum)
			throws BusinessException {
		Driver driver = (Driver) DtoTransitionUtils.trans(Driver.class, driverDto);
		List<Driver> drivers = this.driverMapper.queryDriverInfoByPage(page, driver, companyNum);
		List<DriverDto> dList = null;
		if (null != drivers) {
			dList = new ArrayList<>(drivers.size());
			for (Driver driver2 : drivers) {
				DriverDto dto = (DriverDto) DtoTransitionUtils.trans(DriverDto.class, driver2);
				dList.add(dto);
			}
		}
		return dList;
	}

	@Override
	public Integer findDriverInfoByPageCount(DriverDto driverDto, String companyNum) throws BusinessException {
		Driver driver = (Driver) DtoTransitionUtils.trans(Driver.class, driverDto);
		Integer count = this.driverMapper.queryDriverInfoByPageCount(driver, companyNum);
		return count;
	}

	@Override
	@Transactional
	@CacheEvict(value="usedEdit",key="'findDriverIdAndRealName'")
	@SystemServiceLog(description="增加司机")
	public void addDriverAndDriverComnumInfo(DriverDto driverDto, String companyNum) throws BusinessException {
		if (null == driverDto || StringUtils.isBlank(companyNum)) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.DATA_SECURITY.code());
		}
		Driver driver = (Driver) DtoTransitionUtils.trans(Driver.class, driverDto);
		//创建司机编号
		String driverNum = MarkNumUtil.getNo(GenerateNumConstants.DRIVER);
		//设置创建好的司机编号
		driver.setDriverNum(driverNum);
		//设置成公司司机 0公司司机，1社会司机
		driver.setDriverIsCompany(DriverIsCompanyEnum.company_driver.getCode());
		//设置流程，1为已添加手机号码
		driver.setDriverFlag(1);
		//从ehcache中的sendSMS获取验证码
		Cache cache = this.ehCacheCacheManager.getCache("sendSMS");
		//获取这个手机号下的缓存的验证码，验证码在缓存xx分钟
		String code = cache.get(driverDto.getDriverPhone(), String.class);
		logger.info("缓存名：{}，缓存中的验证码：{}，输入的验证码：{}", cache.getName(), code, driverDto.getDriverToken());
		//如果验证码在缓存中过时，则重新获取验证码
		if (StringUtils.isBlank(code)) {
			throw new BusinessException("请重新获取验证码", PlatFormErrorCode.DRIVER_TOKEN.code());
		}
		//如果输入的验证码不正确
		if (!code.equals(driverDto.getDriverToken())) {
			throw new BusinessException("验证码错误", PlatFormErrorCode.DRIVER_TOKEN.code());
		}
		//设置插入时间
		driver.setDriverInsTime(new Date());
		int result = this.driverMapper.insertDriverInfo(driver);
		if (result == 0) {
			throw new BusinessException("增加司机失败", PlatFormErrorCode.DATA_SECURITY.code());
		}
		DriverComnum driverComnum = new DriverComnum();
		//设置司机编号
		driverComnum.setDriverNum(driverNum);
		//设置公司编号
		driverComnum.setComnumNum(companyNum);
		//设置插入时间
		driverComnum.setAssociInsTime(new Date());
		//保存司机-公司关系信息
		int count = this.driverComnumMapper.insertDriverComnumInfo(driverComnum);
		if (count == 0) {
			throw new BusinessException("增加司机失败", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}
	
	@Override
	@Transactional
	public void addDriverComnumInfo(String driverNum, String companyNum) throws BusinessException {
		DriverComnum driverComnum = new DriverComnum();
		//设置司机编号
		driverComnum.setDriverNum(driverNum);
		//设置公司编号
		driverComnum.setComnumNum(companyNum);
		//设置插入时间
		driverComnum.setAssociInsTime(new Date());
		//执行保存 司机-公司 关系
		int result = this.driverComnumMapper.insertDriverComnumInfo(driverComnum);
		if (result == 0) {
			throw new BusinessException("增加司机失败", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}
	
	@Override
	@Cacheable(value="nameExist",key="#driverName")
	public Integer findDriverInfoExist(String driverName) throws BusinessException {
		if (StringUtils.isBlank(driverName)) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		//通过司机用户名，在正在审核和审核通过中，查询是否存在
		Integer result = this.driverMapper.queryDriverInfoExist(driverName, DriverToExamineEnum.audit_failed.getCode());
		return result;
	}

	@Override
	public String findDriverNumByName(String driverName) throws BusinessException {
		if (StringUtils.isBlank(driverName)) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		String driverNum = this.driverMapper.queryDriverNumByName(driverName);
		return driverNum;
	}

	@Override
	public void delDriverAndComnum(String driverNum, String comnumNum) throws BusinessException {
		if (StringUtils.isBlank(driverNum) || StringUtils.isBlank(comnumNum)) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		this.driverComnumMapper.deleteDriverComnumInfo(driverNum, comnumNum);
	}

	@Override
	@Cacheable(value="usedEdit",key="#driverId")
	public DriverDto findDriverDetailsById(Long driverId) throws BusinessException {
		Driver driver = this.driverMapper.queryDriverDetailsById(driverId);
		DriverDto driverDto = (DriverDto) DtoTransitionUtils.trans(DriverDto.class, driver);
		return driverDto;
	}

	@Override
	@Transactional
	public void modifyDriverToExamine(int toExamine, Long driverId) throws BusinessException {
		int count = this.driverMapper.updateDriverToExamine(toExamine, driverId);
		if (count == 0) {
			throw new BusinessException("修改审核失败", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}

	@Override
	@Transactional
	@SystemServiceLog(description="修改司机是否禁用")
	public void modifyDriverDisable(Integer isDelete, String driverNum) throws BusinessException {
		int count = this.driverMapper.updateDriverDisable(isDelete, driverNum);
		if (count == 0) {
			String msg = "";
			if (isDelete == 0) {
				msg = "启用失败";
			}else if (isDelete == 1) {
				msg = "禁用失败";
			}else {
				msg = "数据异常，操作失败";
			}
			throw new BusinessException(msg, PlatFormErrorCode.DATA_SECURITY.code());
		}
	}

	@Override
	@Transactional
	public String shortDriverOpenAcc(String driverNum, String accBank, String cardNo, String cardName,
			String driverIdCard, String mobileNo) throws BusinessException {
		
		if (StringUtils.isBlank(driverNum) || StringUtils.isBlank(accBank) || StringUtils.isBlank(cardNo) ||
				StringUtils.isBlank(cardName) || StringUtils.isBlank(driverIdCard) || StringUtils.isBlank(mobileNo)) {
			throw new BusinessException("开户信息不能为空！", PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code());
		}
		AccManageData accManageData = new AccManageData();
		accManageData.setCustNo(DateUtils.getCurDtsStr() + RandomCharData.createData(8));	//设置客户号
		accManageData.setAccType(AccTypeEnum.TO_PRIVATE.getDesc());	//设置账户类型：00对私，01对公
		accManageData.setAccBank(accBank);	//设置开户银行如：中国银行
		accManageData.setCardNo(cardNo);	//设置银行卡号
		accManageData.setCardName(cardName);	//设置持卡人姓名
		accManageData.setIdNo(driverIdCard);	//设置身份证号
		accManageData.setMobileNo(mobileNo);	//设置手机号
		//调用接口进行开户操作
		Map<String, String> resultMap = null;
		String status = "0";	//状态值，0失败，1成功
		try {
			logger.info("开户请求的参数为{}", accManageData.toString());
			resultMap = this.ytFinancialService.getYTFinancialResult(accManageData, 20, "open_acc");
		} catch (Exception e) {
			e.printStackTrace();
			return status;
		}
		//如果返回的是1，则说明账户开户成功
		if (null != resultMap && "1".equals(resultMap.get("status"))) {
			//根据data节点，解析json字符串为 AccManageData 对象
			accManageData = (AccManageData) JsonUtil.jsonToBean(resultMap.get("data"), "data", AccManageData.class);
			//获取账户号并设置
			Driver driver = new Driver(driverNum, AccTypeEnum.TO_PRIVATE.getDesc(), accBank, cardNo, cardName, 
					mobileNo, accManageData.getAccountNo(), driverIdCard);
			//更新开户信息
			int i =  this.driverMapper.updateShortDriverOpenAcc(driver);
			//如果i为0，说明是没有增加成功
			if (i == 0) {
				logger.info("保存开户信息失败，开户信息为：{}", accManageData.toString());
				throw new BusinessException("保存开户信息失败，人工处理！", PlatFormErrorCode.DATA_SECURITY.code());
			}
			status = "1";
		}else {
			logger.info("司机账户开户异常--->{}", resultMap.get("data"));
			//通过 | 分割成数组，获取返回的提示信息
			String message = com.ttbj.core.util.StringUtil.split(resultMap.get("data"), "|")[1];
			throw new BusinessException(message, PlatFormErrorCode.DATA_SECURITY.code());
		}
		return status;
	}

	@Override
	@Transactional
	public String shortDriverAccModify(String driverNum, String accountNo, String accBank, String cardNo, String mobileNo) throws BusinessException {
		if (StringUtils.isBlank(driverNum) || StringUtils.isBlank(accBank) 
				|| StringUtils.isBlank(cardNo) || StringUtils.isBlank(mobileNo)) {
			throw new BusinessException("参数不能为空！", PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code());
		}
		AccManageData accManageData = new AccManageData();
		accManageData.setAccountNo(accountNo);//设置账户号
		accManageData.setAccType(AccTypeEnum.TO_PRIVATE.getDesc());	//设置账户类型：00对私，01对公
		accManageData.setAccBank(accBank);	//设置开户银行如：中国银行
		accManageData.setCardNo(cardNo);	//设置银行卡号
		accManageData.setMobileNo(mobileNo);	//设置手机号
		//调用接口进行账户变更操作
		Map<String, String> resultMap = null;
		String status = "0";	//状态值，0失败，1成功
		try {
			resultMap = this.ytFinancialService.getYTFinancialResult(accManageData, 20, "acc_modify");
		} catch (Exception e) {
			e.printStackTrace();
			return status;
		}
		//如果返回的是1，则说明账户开户成功
		if (null != resultMap && "1".equals(resultMap.get("status"))) {
			//根据data节点，解析json字符串为 AccManageData 对象
			accManageData = (AccManageData) JsonUtil.jsonToBean(resultMap.get("data"), "data", AccManageData.class);
			logger.info("账户变更正常---{}", resultMap.get("data"));
			Driver driver = new Driver(driverNum, accBank, cardNo, mobileNo, accountNo);
			//获取新账户号并更新
			int i = this.driverMapper.updateShortDriverOpenAcc(driver);
			//如果i为0，说明是没有增加成功
			if (i == 0) {
				logger.info("保存变更信息失败，变更后的账户号：{}", accManageData.getAccountNo());
				throw new BusinessException("账户变更更新失败，人工处理！", PlatFormErrorCode.DATA_SECURITY.code());
			}
			status = "1";
		}else {
			logger.info("账户变更异常--->{}", resultMap.get("data"));
			//通过 | 分割成数组，获取返回的提示信息
			String message = com.ttbj.core.util.StringUtil.split(resultMap.get("data"), "|")[1];
			throw new BusinessException(message, PlatFormErrorCode.DATA_SECURITY.code());
		}
		return status;
	}


	@Override
	@CachePut(value="sendSMS", key="#phone")
	public String sendSmsToDriver(String phone, int length) throws BusinessException {
		//使用正则验证手机号是否合法
		boolean flag = RegexUtil.isMobileNo(phone);
		if (!flag) {
			throw new BusinessException("请输入正确的手机号", PlatFormErrorCode.DATA_SECURITY.code());
		}
		//随机生成length位验证码
		String code = RandomStringUtils.random(length, false, true);
		// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的用户,您的验证码为${code}"时,此处的值为
		String jsonObjectStringParams = "{\"code\":\"" + code + "\"}";
		// 必填:短信签名-可在短信控制台中找到
		String signName = SmsEnum.SIGNNAME.getValue();
		// 必填:短信模板-可在短信控制台中找到
		String templateCode = SmsEnum.TEMPLATECODE.getValue();
		try {
			//发送验证码
			SendSmsResponse smsResponse = SendSMSUtil.sendSms(phone, jsonObjectStringParams, signName, templateCode);
			logger.info("发送的验证码：{}", code);
			//如果发送成功，把验证码保存到sendSMS缓存中
			if(StringUtils.isNotBlank(smsResponse.getCode()) && smsResponse.getCode().equals("OK")){
                return code;
	        }else {	//如果发送失败
	        	throw new BusinessException("验证码发送失败，重新发送", PlatFormErrorCode.DATA_SECURITY.code());
	        }
		} catch (ClientException e) {
			throw new BusinessException("发送验证码错误，重新发送", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}

	@Override
	@Cacheable(value="usedEdit",key="#root.methodName")
	public List<DriverDto> findDriverIdAndRealName() throws BusinessException {
		List<Driver> drivers = this.driverMapper.queryDriverIdAndRealName(DriverIsDelEnum.not_del.getCode());
		List<DriverDto> driverDtos = new ArrayList<>();
		for (Driver driver : drivers) {
			DriverDto driverDto = (DriverDto) DtoTransitionUtils.trans(DriverDto.class, driver);
			driverDtos.add(driverDto);
		}
		return driverDtos;
	}

	@Override
	@CacheEvict(value="usedEdit",key="#id")
	public void editRealNameById(String realName, Long id) throws BusinessException {
		this.driverMapper.updateRealNameById(realName, id);
	}

	
	@Override
	public List<DriverDto> findDriverAndComInfo() {
		List<DriverDto> dtos = this.driverComnumMapper.queryDriverAndComInfo(DriverIsDelEnum.not_del.getCode());
		return dtos;
	}
}
